package com.dyava.commons.thread;


import org.apache.commons.io.IOUtils;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 注册需要释放的资源，统一释放
 * Created by jjliu on 2017/9/12.
 */
public class ThreadLocalUtils {
    public static interface OnException{
        public void onException(Exception e);
    }
    static OnException onException=null; //异常时的处理
    static ArrayList<Runnable> onFinishRunList = new ArrayList<Runnable>();//每次都会执行的动作,启动时配置

    static ThreadLocal<Map<String,Object>> cacheThreadLocal = new ThreadLocal<Map<String,Object>>(); //线程级缓存
    static ThreadLocal<List<Object>> finishListThreadLocal = new ThreadLocal<List<Object>>();  //线程级动作或者需要关闭的对象

    static {
        cacheThreadLocal.set(new HashMap<String, Object>());
        finishListThreadLocal.set(new ArrayList<Object>());
    }

    private static Map<String,Object> getCacheThreadLocal(){
        Map<String,Object> map =  cacheThreadLocal.get();
        if(map==null){
            map = new HashMap<String,Object>();
            cacheThreadLocal.set(map);
        }
        return map;
    }
    private static List<Object> getFinishListThreadLocal(){
        List<Object> list = finishListThreadLocal.get();
        if(list==null){
            list = new ArrayList<Object>();
            finishListThreadLocal.set(list);
        }
        return list;
    }

    public static void cachePut(String key,Object value){
        getCacheThreadLocal().put(key,value);
    }
    public static <T> T cachePutIfAbsent(String key,Object value){
        Map<String, Object> map = getCacheThreadLocal();
        Object v = map.get(key);
        if(v == null){
            map.put(key,value);
            return null;
        }else{
            return (T)v;
        }
    }



    public static<T> T cacheGet(String key){
        return (T)getCacheThreadLocal().get(key);
    }
    public static void cacheRemove(String key){
        getCacheThreadLocal().remove(key);
    }

    public static void finishClose(Closeable closeable){
        getFinishListThreadLocal().add(closeable);
    }
    public static void finishRun(Runnable runnable){
        getFinishListThreadLocal().add(runnable);
    }

    public static void addOnFinishRun(Runnable runnable){
        onFinishRunList.add(runnable);
    }
    public static void setOnException(OnException onExceptionFn){
        onException = onExceptionFn;
    }

    public static void finish(){
        {
            int len = onFinishRunList.size();
            for(int i=len-1; i>=0;i--){
                Runnable itemObj = onFinishRunList.get(i);
                doFinishrun(itemObj);
            }
        }
        {
            List<Object> itemList = getFinishListThreadLocal();
            int len = itemList.size();
            for(int i=len-1; i>=0;i--){
                Object item = itemList.get(i);
                if(item instanceof Closeable){
                    Closeable itemObj = (Closeable)item;
                    IOUtils.closeQuietly(itemObj);
                }else if(item instanceof Runnable){
                    Runnable itemObj = (Runnable)item;
                    doFinishrun(itemObj);
                }
            }
            itemList.clear();
        }
        getCacheThreadLocal().clear();
    }
    private static void doFinishrun(Runnable itemObj) {
        try {
            itemObj.run();
        }catch (Exception e){
            e.printStackTrace();
            if(onException!=null){
                onException.onException(e);
            }
        }
    }
}
